package com.auntvt.timo.jpax.springbootstarter.service.impl;

import com.auntvt.timo.jpax.core.exception.JpaxRepositoryException;
import com.auntvt.timo.jpax.core.service.impl.ChainQuickServiceMulti;
import com.auntvt.timo.jpax.core.service.impl.JpaServiceImpl;
import com.auntvt.timo.jpax.core.service.impl.QuickServiceMulti;
import com.auntvt.timo.jpax.core.utils.RepositoryUtil;
import com.auntvt.timo.jpax.springbootstarter.helper.LogicDelete;
import com.auntvt.timo.jpax.springbootstarter.helper.PageHelper;
import com.auntvt.timo.jpax.springbootstarter.repository.JpaxRepository;
import com.auntvt.timo.jpax.springbootstarter.service.JpaxService;
import com.auntvt.timo.jpax.springbootstarter.utils.AssertUtil;
import com.auntvt.timo.jpax.springbootstarter.utils.EntityUtil;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

/**
 * Service基类（泛型：T 实体类、ID 主键类型）
 *
 * @author 小懒虫 <auntvt@163.com>
 * @date 2021/5/25
 */
public class JpaxServiceImpl<T, ID> extends JpaServiceImpl<T, ID> implements JpaxService<T, ID>, QuickServiceMulti<T>, ChainQuickServiceMulti<T> {

    /**
     * 对应实体类的持久层Repository
     */
    private JpaxRepository<T, ID> repository;

    /**
     * 获取对应实体类的持久层Repository接口
     *
     * @return Repository接口
     */
    @Override
    @SuppressWarnings("unchecked")
    public JpaxRepository<T, ID> getRepository() {
        if (repository == null) {
            repository = RepositoryUtil.getMatchRepository(JpaxRepository.class, this.getClass());
        }
        return repository;
    }

    /**
     * 获取分页列表数据
     *
     * @return 返回分页数据
     */
    @Override
    public Page<T> pages() {
        // 构建分页对象
        PageRequest page = PageHelper.pageRequest();
        return getRepository().findAll(page);
    }

    /**
     * 根据查询实例提交获取分页列表数据
     *
     * @param example 查询实例
     * @return 返回分页数据
     */
    @Override
    public Page<T> pages(Example<T> example) {
        // 创建分页对象
        PageRequest page = PageHelper.pageRequest();
        return getRepository().findAll(example, page);
    }

    /**
     * 逻辑删除数据
     *
     * @param entity 实体类对象
     */
    @Override
    public void logicDelete(T entity) {
        AssertUtil.notNull(entity, "删除数据不能为null");
        try {
            EntityUtil.setField(entity, LogicDelete.FIELD_NAME, LogicDelete.DELETE_VALUE);
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new JpaxRepositoryException("{0}#{1}字段类型不正确，请使用Boolean或数字类型！", entity.getClass().getName(), LogicDelete.FIELD_NAME);
        } catch (NoSuchMethodException e) {
            throw new JpaxRepositoryException("{0}#{1}逻辑删除字段不存在！", entity.getClass().getName(), LogicDelete.FIELD_NAME);
        }
        save(entity);
    }

    /**
     * 根据主键ID逻辑删除数据
     *
     * @param id 主键ID
     */
    @Override
    public void logicDeleteById(ID id) {
        logicDelete(getById(id));
    }

    /**
     * 根据主键ID列表逻辑删除数据
     *
     * @param ids 主键ID列表
     */
    @Override
    public void logicDeleteByIds(List<ID> ids) {
        for (ID id : ids) {
            logicDeleteById(id);
        }
    }

    /**
     * 逻辑删除全部数据
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void logicDeleteAll() {
        for (T list : lists()) {
            logicDelete(list);
        }
    }

    /**
     * 逻辑删除列表数据
     *
     * @param entities 数据列表
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void logicDeleteAll(Iterable<? extends T> entities) {
        for (T list : entities) {
            logicDelete(list);
        }
    }
}
